package kz.pompei.ifacer.cursor_manager.def;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import kz.pompei.ifacer.cursor_manager.CursorManager;
import kz.pompei.ifacer.model.CursorInfo;

public class DefCursorManager implements CursorManager {
  
  private final Map<CursorInfo, Cursor> cache = new HashMap<>();
  
  private Cursor defCursor = null;
  
  @Override
  public Cursor getCursor(CursorInfo cursorInfo) {
    if (cursorInfo == null) {
      if (defCursor == null) {
        defCursor = createCursor(null);
      }
      return defCursor;
    }
    
    {
      Cursor ret = cache.get(cursorInfo);
      
      if (ret == null) {
        ret = createCursor(cursorInfo);
        cache.put(cursorInfo, ret);
      }
      
      return ret;
    }
  }
  
  private Cursor createCursor(CursorInfo cursorInfo) {
    if (cursorInfo == null) {
      return createNullCursor();
    }
    
    switch (cursorInfo.kind) {
    case DEF:
      return createDefCursor(cursorInfo.params);
      
    case MOVE:
      return createMoveCursor(cursorInfo.params);
      
    case RESIZE_E:
      return new Cursor(Cursor.E_RESIZE_CURSOR);
      
    case RESIZE_HOR:
      return new Cursor(Cursor.E_RESIZE_CURSOR);
      
    case RESIZE_N:
      return new Cursor(Cursor.N_RESIZE_CURSOR);
      
    case RESIZE_NE:
      return new Cursor(Cursor.NE_RESIZE_CURSOR);
      
    case RESIZE_NW:
      return new Cursor(Cursor.NW_RESIZE_CURSOR);
      
    case RESIZE_S:
      return new Cursor(Cursor.S_RESIZE_CURSOR);
      
    case RESIZE_SE:
      return new Cursor(Cursor.SE_RESIZE_CURSOR);
      
    case RESIZE_SW:
      return new Cursor(Cursor.SW_RESIZE_CURSOR);
      
    case RESIZE_W:
      return new Cursor(Cursor.W_RESIZE_CURSOR);
      
    default:
      return new Cursor(Cursor.DEFAULT_CURSOR);
    }
  }
  
  float fontHeight = 10f;
  
  private Cursor createMoveCursor(String params) {
    int pwidth = 0, pheight = 0;
    if (params != null) {
      BufferedImage testImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
      Graphics2D gt = testImage.createGraphics();
      gt.setFont(gt.getFont().deriveFont(fontHeight));
      pwidth = gt.getFontMetrics().stringWidth(params);
      pheight = gt.getFontMetrics().getHeight();
      gt.dispose();
    }
    
    int width = 23, height = 23;
    if (pwidth > 0 && pheight > 0) {
      width = 0 + pwidth;
      if (width < 23) width = 23;
      height = 23 + pheight + 7;
    }
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    g.setColor(Color.WHITE);
    drawMoveCursor(params, pheight, g, 0, 0);
    drawMoveCursor(params, pheight, g, 1, 0);
    drawMoveCursor(params, pheight, g, 2, 0);
    drawMoveCursor(params, pheight, g, 0, 1);
    drawMoveCursor(params, pheight, g, 2, 1);
    drawMoveCursor(params, pheight, g, 0, 2);
    drawMoveCursor(params, pheight, g, 1, 2);
    drawMoveCursor(params, pheight, g, 2, 2);
    g.setColor(Color.BLACK);
    drawMoveCursor(params, pheight, g, 1, 1);
    g.dispose();
    
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    
    Point hotSpot = new Point(11, 11);
    
    return toolkit.createCustomCursor(image, hotSpot, "MoveCursor" + rnd.nextInt());
  }
  
  private final Random rnd = new Random();
  
  private void drawMoveCursor(String params, int pheight, Graphics2D g, int x, int y) {
    g.drawLine(x, y + 10, x + 20, y + 10);
    g.drawLine(x, y + 10, x + 4, y + 10 - 3);
    g.drawLine(x, y + 10, x + 4, y + 10 + 3);
    g.drawLine(x + 20 - 4, y + 10 - 3, x + 20, y + 10);
    g.drawLine(x + 20 - 4, y + 10 + 3, x + 20, y + 10);
    
    g.drawLine(x + 10, y + 0, x + 10, y + 20);
    g.drawLine(x + 10, y + 0, x + 10 + 3, y + 4);
    g.drawLine(x + 10, y + 0, x + 10 - 3, y + 4);
    g.drawLine(x + 10, y + 20, x + 10 + 3, y + 20 - 4);
    g.drawLine(x + 10, y + 20, x + 10 - 3, y + 20 - 4);
    if (params != null) {
      g.setFont(g.getFont().deriveFont(fontHeight));
      g.drawString(params, x, y + 17 + pheight);
    }
  }
  
  private Cursor createDefCursor(String params) {
    int pwidth = 0, pheight = 0;
    if (params != null) {
      BufferedImage testImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
      Graphics2D gt = testImage.createGraphics();
      gt.setFont(gt.getFont().deriveFont(fontHeight));
      pwidth = gt.getFontMetrics().stringWidth(params);
      pheight = gt.getFontMetrics().getHeight();
      gt.dispose();
    }
    
    int width = 11, height = 11;
    if (pwidth > 0 && pheight > 0) {
      width = 0 + pwidth;
      if (width < 11) width = 11;
      height = 11 + pheight + 3;
    }
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    g.setColor(Color.BLACK);
    g.drawLine(5, 0, 5, 10);
    g.drawLine(0, 5, 10, 5);
    if (params != null) {
      g.setFont(g.getFont().deriveFont(fontHeight));
      g.drawString(params, 0, 7 + pheight);
    }
    g.dispose();
    
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    
    Point hotSpot = new Point(5, 5);
    
    return toolkit.createCustomCursor(image, hotSpot, "DefCursor" + rnd.nextInt());
  }
  
  private Cursor createNullCursor() {
    BufferedImage image = new BufferedImage(3, 3, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, 3, 3);
    g.setColor(Color.BLACK);
    g.drawLine(1, 1, 1, 1);
    g.dispose();
    
    Toolkit toolkit = Toolkit.getDefaultToolkit();
    
    Point hotSpot = new Point(1, 1);
    
    return toolkit.createCustomCursor(image, hotSpot, "NullCursor");
  }
}
